package com.m2soft.streaming
{
	import com.m2soft.events.*;
	
	import flash.display.*;
	import flash.events.ErrorEvent;
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.events.IEventDispatcher;
	import flash.events.IOErrorEvent;
	import flash.events.SecurityErrorEvent;
	import flash.geom.*;
	import flash.net.*;
	import flash.system.LoaderContext;
	import flash.utils.*;
        
	// Report Loader of HTTP request
	[Event(name="onDocumentLoadedError", type="flash.events.ErrorEvent")]		
	public class ReportLoader implements IEventDispatcher
	{
		private var dispatcher:IEventDispatcher = new EventDispatcher();

		// for web request
		private var m_arr_stream : Array = new Array();	// array of request (URLStream)
		private var m_arr_request : Array = new Array();		// array of request type (URLRequest)

		// extra parameter
		private var m_loaderCtx : LoaderContext;
		private var m_responseHandler : Function;
		private var m_pageLoadHandler : Function;
		private var m_documentLoadedErrorHandler : Function;

		// kth #1461 [한국대학교육협의회] Flash Reporting 동작 방식 변경
		private var swfStream_opt: int = 0;
		private var m_pageProgressHandler: Function;
		private var isFirstResponse: Boolean = true;
		private var headerBytes : ByteArray = null;
		private var pageBytes : ByteArray = null;
		private var curPageSwf: int = 0;
		private var progressTimerId: uint = 0;
		private var isProgressCanceled: Boolean = false;
		private var progressTimeout: int = 10000;
		private var isPacketReceiveDone: Boolean = false;
		
		// kth 2343 [Flash Viewer] mml 포맷을 읽어서 표현하도록 지원. head, page별 xml 저장함
		private var mmlType: int = 0;
		private var m_pageMmlHandler: Function;
		private var isMmlHeadStart: Boolean = false;
		private var isMmlHeadEnd: Boolean = false;
		private var isMmlPageStart: Boolean = false;
		
		private var mmlHeadStartPos: int = -1;
		private var mmlPageStartPos: int = -1;
		
//		private var mmlRemainBytes : ByteArray = null;
		private var mmlBuffer : String = "";
		private var curMmlPage: int = 0;
		private var mmlTimerId: uint = 0;
		private var isMmlCanceled: Boolean = false;
		private var mmlTimeout: int = 10000;
		private var isMmlReceiveDone: Boolean = false;
		
		//
		public function ReportLoader()
		{
			super();
		}

		//
		public function Clear() : void
		{
			for (var i: int=0; i<m_arr_stream.length; i++)
			{
				var st : URLStream = m_arr_stream[i];
				if (st.connected)
					st.close();
			}
			
			m_arr_stream = new Array();
			m_arr_request = new Array();
		}
		
		// kth #1461 [한국대학교육협의회] Flash Reporting 동작 방식 변경
		public function setParam(
				loaderCtx : LoaderContext,
				responseHandler : Function,
				pageLoadHandler : Function,
				documentLoadedErrorHandler : Function,
				pageProgressHandler : Function,
				pageMmlHandler : Function
			) : void
		{
			m_loaderCtx = loaderCtx;
			m_responseHandler = responseHandler;
			m_pageLoadHandler = pageLoadHandler;
			m_documentLoadedErrorHandler = documentLoadedErrorHandler;
			// kth #1461 [한국대학교육협의회] Flash Reporting 동작 방식 변경
			m_pageProgressHandler = pageProgressHandler;
			
			// kth 2343 [Flash Viewer] mml 포맷을 읽어서 표현하도록 지원. head, page별 xml 저장함
			m_pageMmlHandler = pageMmlHandler;
		}
		
		// kth #1461 [한국대학교육협의회] Flash Reporting 동작 방식 변경
		public function setSwfStreamOpt(opt:int): void
		{
			swfStream_opt = opt;
		}
		
		// kth 2343 [Flash Viewer] mml 포맷을 읽어서 표현하도록 지원. head, page별 xml 저장함
		public function setMmlType(type: int): void
		{
			mmlType = type;
		}
		
		// kth add 2012.08.21
		public function setProgressTimeout(timeout: int): void
		{
			if (timeout > 3000)
				progressTimeout = timeout;
		}
		
		//
		public function load(request : URLRequest) : void
		{
			var st : URLStream = new URLStream();
			
			m_arr_stream.push(st);
			m_arr_request.push(request);
		
			st.addEventListener(Event.COMPLETE, responseHandler);
			st.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);
			st.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler);
			
			st.load(request);
		}

		// kth #1461 [한국대학교육협의회] Flash Reporting 동작 방식 변경
		public function loadStream(request : URLRequest) : void
		{
			var st : URLStream = new URLStream();
			
			m_arr_stream.push(st);
			m_arr_request.push(request);

			// kth #2133 [우석대학교] 처음 FileOpen() 하여 보고서를 호출하였을 때는 정상. 조건을 바꾸어 재호출시 이상
			progressInit(0);
			isProgressCanceled = false;
			
			st.addEventListener(flash.events.ProgressEvent.PROGRESS, progressHandler);
			st.addEventListener(Event.COMPLETE, progressHandler);
			st.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);
			st.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler);
			
			st.load(request);
		}

		// kth 2343 [Flash Viewer] mml 포맷을 읽어서 표현하도록 지원. head, page별 xml 저장함
		public function loadMml(request : URLRequest) : void
		{
			var st : URLStream = new URLStream();
			
			m_arr_stream.push(st);
			m_arr_request.push(request);
			
			mmlInit(0);
			isMmlCanceled = false;
			
//			st.addEventListener("httpResponseStatus", responseStatusMmlHandler);
			st.addEventListener(flash.events.ProgressEvent.PROGRESS, mmlHandler);
			st.addEventListener(Event.COMPLETE, mmlHandler);
			st.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);
			st.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler);
			
			st.load(request);
		}
		
		
		// kth 2343 [Flash Viewer] mml 포맷을 읽어서 표현하도록 지원. head, page별 xml 저장함
		private function responseStatusMmlHandler(event : flash.events.HTTPStatusEvent):void
		{
			var i: int;
			
			var res : Array = event.responseHeaders as Array;
			var st : URLStream = event.target as URLStream;
			var bytes : ByteArray = new ByteArray();
			var message : String;
			var message_len: int;
			
			if (event.status == 200) {
				for ( i = 0; i < res.length; i++ ) {
					if (res[i].name == "crownix-status" && res[i].value == "error") {
						st.readBytes(bytes);
						st.close();
						if (bytes.bytesAvailable >= 2)
							bytes.position += 2;
						message_len = bytes.bytesAvailable;
						message = bytes.readUTFBytes(message_len);
						m_documentLoadedErrorHandler.call(null, message);
						
						isMmlCanceled = true;
						st.removeEventListener(Event.COMPLETE, mmlHandler);
						st.removeEventListener(flash.events.ProgressEvent.PROGRESS, mmlHandler);
						break;
					}
				}
			}
			else {
				isMmlCanceled = true;
				st.removeEventListener(Event.COMPLETE, mmlHandler);
				st.removeEventListener(flash.events.ProgressEvent.PROGRESS, mmlHandler);
			}
		}
		
		
		
		//
		public function clearCheckRequest() : void
		{
			for (var i: int=0; i<m_arr_stream.length;)
			{
				var req : URLRequest = m_arr_request[i];
				var params : URLVariables = req.data as URLVariables;
				
				if (params.opcode == "601")	// check if complete 
				{
					var st : URLStream = m_arr_stream[i];
					if (st.connected)
						st.close();
					
					m_arr_stream.splice(i, 1);				
					m_arr_request.splice(i, 1);				
					continue;
				}
				
				i++;
			}
		}
		
		//
		public function clearReportRequest() : void
		{
			for (var i: int=0; i<m_arr_stream.length;)
			{
				var req : URLRequest = m_arr_request[i];
				var params : URLVariables = req.data as URLVariables;
				
				if (params.opcode == "603" || params.opcode == "604")	// report or cancel report 
				{
					var st : URLStream = m_arr_stream[i];
					if (st.connected)
						st.close();
					
					m_arr_stream.splice(i, 1);				
					m_arr_request.splice(i, 1);				
					continue;
				}
				
				i++;
			}
		}
		
		// event handler for HTTP response
		private function responseHandler(event:Event):void
		{
			var bytes : ByteArray = new ByteArray();

			var st : URLStream = event.target as URLStream;
			st.readBytes(bytes);
			st.close();

			for (var i : int=0; i<m_arr_stream.length; i++)
			{
				if (st == m_arr_stream[i])
				{
					var params : URLVariables = m_arr_request[i].data as URLVariables;
					
					bytes.endian = Endian.BIG_ENDIAN;

					m_responseHandler.call(null, params, bytes);
					break;
				}
			}
		}

		// kth #1461 [한국대학교육협의회] Flash Reporting 동작 방식 변경
		public function progressInit(status:int): void
		{
			isFirstResponse = true;
			headerBytes = null;
			pageBytes = null;
			curPageSwf = 0;
			progressTimerId = 0;
			if (status == 4) // canceled
				isProgressCanceled = true;
			m_pageProgressHandler.call(null, null, status);
		}
		
		// kth #1461 [한국대학교육협의회] Flash Reporting 동작 방식 변경
		private function progressError(): void
		{
			progressInit(0); // init
			if (!isProgressCanceled)
				m_documentLoadedErrorHandler.call(null, "network progress error");
		}
			
		// kth #1461 [한국대학교육협의회] Flash Reporting 동작 방식 변경
		// event handler for HTTP progress, response
		private function progressHandler(event:Event):void
		{
			var i: int;
			var resSize: uint;
			var resCode: uint;
			var pageSize: uint;
			var message: String;
			
			var tmpBytes: ByteArray = null;
			var bytes : ByteArray = new ByteArray();
			
			var st : URLStream = event.target as URLStream;
			
			st.readBytes(bytes);
			//st.close(); 연결상태를 끊지 않는다.
			
			if (progressTimerId != 0)
				clearTimeout(progressTimerId);

			if (isProgressCanceled || isPacketReceiveDone) {
				st.close();
				isPacketReceiveDone = false;
				return;
			}
			
			if (isFirstResponse) {
				if (headerBytes == null)
					headerBytes = new ByteArray();
				headerBytes.writeBytes(bytes);
				
				headerBytes.position = 0;
				if (headerBytes.bytesAvailable < 7) { // headersize
					if (isPacketReceiveDone) {
						st.close();
						isPacketReceiveDone = false;
					}
					else {
						st.addEventListener(flash.events.ProgressEvent.PROGRESS, progressHandler);
						progressTimerId = setTimeout(progressError, progressTimeout);
					}
					return;
				}
				
				resSize = headerBytes.readUnsignedInt();
				resCode = uint(headerBytes.readUTFBytes(resSize));
				
				if (resCode == 500) { // error
					if (headerBytes.bytesAvailable >= 4) {
						resSize = headerBytes.readUnsignedInt();
						if (headerBytes.bytesAvailable >= resSize)
							message = headerBytes.readUTFBytes(resSize);
						else
							message = "unknown error(network error)";
					}
					else {
						message = "network packet error[1]";
					}
					st.close(); // socket도  close하고  event도 발생시키지 않는다.
					progressInit(0); // init
					m_documentLoadedErrorHandler.call(null, message);
					return;
				}
				
				isFirstResponse = false;
				
				if (pageBytes == null)
					pageBytes = new ByteArray();
				pageBytes.clear();
				
				pageBytes.writeBytes(headerBytes, 7);
				headerBytes = null;
			}
			else {
				if (pageBytes == null)
					pageBytes = new ByteArray();
				pageBytes.writeBytes(bytes);
			}
			
			
			pageBytes.position = 0; // 처음으로 돌려주기
			if (pageBytes.bytesAvailable < 4) { // pagesize
				if (isPacketReceiveDone) {
					st.close();
					isPacketReceiveDone = false;
				}
				else {
					st.addEventListener(flash.events.ProgressEvent.PROGRESS, progressHandler);
					progressTimerId = setTimeout(progressError, progressTimeout);
				}
				return;
			}
			pageSize = pageBytes.readUnsignedInt();
			
			if (pageSize <= 3) { // error
				if (pageBytes.bytesAvailable >= pageSize) {
					resCode = uint(pageBytes.readUTFBytes(pageSize));
					
					if (pageBytes.bytesAvailable >= 4) {
						resSize = pageBytes.readUnsignedInt();
						if (pageBytes.bytesAvailable >= resSize)
							message = pageBytes.readUTFBytes(resSize);
						else
							message = "unknown error(page error)";
					}
					else {
						message = "network packet error[2]";
					}
				}
				else {
					message = "network packet error[3]";
				}
				st.close(); // socket도  close하고  event도 발생시키지 않는다.
				progressInit(0); // init
				m_documentLoadedErrorHandler.call(null, message);
				return;
			}
			
			if (pageSize > pageBytes.bytesAvailable) {
				pageBytes.position = pageBytes.length;
				if (isPacketReceiveDone) {
					st.close();
					isPacketReceiveDone = false;
				}
				else {
					st.addEventListener(flash.events.ProgressEvent.PROGRESS, progressHandler);
					progressTimerId = setTimeout(progressError, progressTimeout);
				}
				return;
			}
			
			
//			for (i = 0; i < m_arr_stream.length; i++)
//			{
//				if (st == m_arr_stream[i])
//				{
					var onePage: ByteArray = null;
					var nextPage: int;
					
					while(pageSize <= pageBytes.bytesAvailable) {
						if (pageSize <= 10) { // error 인 경우
							resCode = uint(pageBytes.readUTFBytes(pageSize)); // 500
							// Message
							if (pageBytes.bytesAvailable >= 4)
								resSize = pageBytes.readUnsignedInt();
							else
								resSize = 0;
							
							if (resSize != 0 && pageBytes.bytesAvailable >= resSize)
								message = pageBytes.readUTFBytes(resSize);
							else
								message = "";
							
							st.close();
							progressInit(0); // init
							m_documentLoadedErrorHandler.call(null, message);
							return;
						}
							
						pageBytes.position -= 4;
						if (onePage == null)
							onePage = new ByteArray();
						else
							onePage.clear();
						pageBytes.readBytes(onePage, 0, pageSize+4);
						
						onePage.endian = Endian.BIG_ENDIAN;
						m_pageProgressHandler.call(null, onePage, curPageSwf);
						curPageSwf++;
						
						onePage.position -= 4;
						nextPage = onePage.readUnsignedInt();
						if (nextPage == 0) { // report done
							if (isPacketReceiveDone) {
								st.close();
								isPacketReceiveDone = false;
							}
							else {
								isPacketReceiveDone = true;
							}
							return;
						}
						
						if (pageBytes.bytesAvailable < 4) { // pagesize
							if (tmpBytes == null)
								tmpBytes = new ByteArray();
							tmpBytes.clear();
							pageBytes.readBytes(tmpBytes, 0, pageBytes.bytesAvailable);
							pageBytes.clear();
							tmpBytes.readBytes(pageBytes, 0, tmpBytes.bytesAvailable);
							
							pageBytes.position = pageBytes.length;
							if (isPacketReceiveDone) {
								st.close();
								isPacketReceiveDone = false;
							}
							else {
								st.addEventListener(flash.events.ProgressEvent.PROGRESS, progressHandler);
								progressTimerId = setTimeout(progressError, progressTimeout);
							}
							return;
						}
						pageSize = pageBytes.readUnsignedInt();
						
						if (pageSize > pageBytes.bytesAvailable) {
							pageBytes.position -= 4;
							
							if (tmpBytes == null)
								tmpBytes = new ByteArray();
							
							tmpBytes.clear();
							pageBytes.readBytes(tmpBytes, 0, pageBytes.bytesAvailable);
							pageBytes.clear();
							tmpBytes.readBytes(pageBytes, 0, tmpBytes.bytesAvailable);
							
							pageBytes.position = pageBytes.length;
							if (isPacketReceiveDone) {
								st.close();
								isPacketReceiveDone = false;
							}
							else {
								st.addEventListener(flash.events.ProgressEvent.PROGRESS, progressHandler);
								progressTimerId = setTimeout(progressError, progressTimeout);
							}
							return;
						}
					}
					
//					break;
//				}
//			}
			
			if (isPacketReceiveDone) {
				st.close();
				isPacketReceiveDone = false;
			}
			else {
				st.addEventListener(flash.events.ProgressEvent.PROGRESS, progressHandler);
				progressTimerId = setTimeout(progressError, progressTimeout);
			}
		}
		
		// kth 2343 [Flash Viewer] mml 포맷을 읽어서 표현하도록 지원. head, page별 xml 저장함
		public function mmlInit(status:int): void
		{
			isMmlHeadStart = false;
			isMmlHeadEnd = false;
			isMmlPageStart = false;
			isMmlReceiveDone = false;
			
//			mmlRemainBytes = null;
			curMmlPage = 0;
			mmlTimerId = 0;
			if (status == 4) // canceled
				isMmlCanceled = true;
			m_pageMmlHandler.call(null, null, status);
		}
		
		// kth 2343 [Flash Viewer] mml 포맷을 읽어서 표현하도록 지원. head, page별 xml 저장함
		private function mmlError(): void
		{
			mmlInit(0); // init
			if (!isMmlCanceled)
				m_documentLoadedErrorHandler.call(null, "network error(mml)");
		}
		
		// kth 2343 [Flash Viewer] mml 포맷을 읽어서 표현하도록 지원. head, page별 xml 저장함
		private function mmlHandler(event:Event):void
		{
			var i: int;
			var resSize: uint;
			var resCode: uint;
			var pageSize: uint;
			var message: String;
			var bytes_size: int;
            var tmpStr: String;
			
			var st : URLStream = event.target as URLStream;
			
			bytes_size = st.bytesAvailable;
			tmpStr = st.readUTFBytes(bytes_size);
			
			//st.close(); 연결상태를 끊지 않는다.
			
			if (mmlTimerId != 0)
				clearTimeout(mmlTimerId);
			
			if (isMmlCanceled || isMmlReceiveDone) {
				st.close();
				isMmlReceiveDone = false;
				return;
			}

			var offset: int;
			mmlBuffer += tmpStr;
			
			if (!isMmlHeadStart) {
				offset = mmlBuffer.search("<HEAD>");
				if (offset == -1) {
					if (bytes_size > 20) {
						offset = mmlBuffer.search("<MML>");
						if (offset == -1) { // eeror
							st.close();
							mmlInit(0); // init
							m_documentLoadedErrorHandler.call(null, mmlBuffer);
							return;
						}
					}
					return;
				}
				isMmlHeadStart = true;
				mmlHeadStartPos = offset;
			}
			
			if (!isMmlHeadEnd) {
				offset = mmlBuffer.search("</HEAD>");
				if (offset == -1) {
					st.addEventListener(flash.events.ProgressEvent.PROGRESS, mmlHandler);
					progressTimerId = setTimeout(mmlError, mmlTimeout);
					return;
				}
				isMmlHeadEnd = true;
				tmpStr = mmlBuffer.substring(mmlHeadStartPos, offset + 7);
				m_pageMmlHandler.call(null, tmpStr, -1); // head
				mmlBuffer = mmlBuffer.substring(offset + 7);
			}
			
			while (isMmlHeadStart && isMmlHeadEnd) {
				if (!isMmlPageStart) {
					offset = mmlBuffer.search("<PG ");
					if (offset == -1) {
						offset = mmlBuffer.search("</BODY>");
						if (offset == -1) {
							st.addEventListener(flash.events.ProgressEvent.PROGRESS, mmlHandler);
							mmlTimerId = setTimeout(mmlError, mmlTimeout);
							break;
						}
						
						m_pageMmlHandler.call(null, null, 3); // complete
						
						st.close();
						if (isMmlReceiveDone)
							isMmlReceiveDone = false;
						else
							isMmlReceiveDone = true;
						break;
					}
					isMmlPageStart = true;
					mmlPageStartPos = offset;
				}
				
				offset = mmlBuffer.search("</PG>");
				if (offset == -1) {
					st.addEventListener(flash.events.ProgressEvent.PROGRESS, mmlHandler);
					mmlTimerId = setTimeout(mmlError, mmlTimeout);
					break;
				}
				
				tmpStr = mmlBuffer.substring(mmlPageStartPos, offset + 5);
				m_pageMmlHandler.call(null, tmpStr, curMmlPage);
				
				mmlBuffer = mmlBuffer.substring(offset + 5);
				
				curMmlPage++;
				isMmlPageStart = false;
			}
		}
		
		// start_page : 1, 2, ...
		public function parsePage(start_page : int, count_page : int, bytes : ByteArray) : void
		{
			var initpos : uint = bytes.position;
			
			bytes.endian = Endian.BIG_ENDIAN;

			// check if MRF file
			var mrfSignature: String = bytes.readUTFBytes(3);
			if (mrfSignature == "MRF")
			{
				var mrfVersion: String = bytes.readUTFBytes(3);
				if (mrfVersion != "1.0")
					return;
					
				var pageCount: int = Math.min(bytes.readInt(), count_page);
				var pageHeaderLength: int = bytes.readInt();
	
				var arrPageBytes : Array = new Array(pageCount);
				
				for(var i : int =0; i<pageCount; i++)
				{
					bytes.position = initpos + 3 + 3 + 4 + 4 + i * (4 * 2);
					var startPage: int = bytes.readInt();
					var lenPage: int = bytes.readInt();
	
					var sub_inputBytes: ByteArray = new ByteArray();
					
					bytes.position = initpos + 3 + 3 + 4 + 4 + pageHeaderLength + startPage;
					bytes.readBytes(sub_inputBytes, 0, lenPage);
					
					arrPageBytes[i] = sub_inputBytes; 
				}
			}
			else
			{
				arrPageBytes = new Array(1);
				arrPageBytes[0] = bytes;
			}

			// correct flash version
			for(i=0; i<arrPageBytes.length; i++)
			{
				bytes = arrPageBytes[i];
				bytes.position = 0;
				
				bytes.endian = Endian.LITTLE_ENDIAN;
				
				if (isCompressed(bytes)) {
					uncompress(bytes);
				}
				
				
				var loader: Loader = new Loader();
				loader.name = "pageloader-" + String(start_page + i);
				loader.contentLoaderInfo.addEventListener(Event.COMPLETE, m_pageLoadHandler);
				loader.loadBytes(bytes, m_loaderCtx);
			}
		}
		
		public function parseSwfPage(page: int, swfBytes : ByteArray) : void
		{
			swfBytes.endian = Endian.BIG_ENDIAN;
			swfBytes.position = 0;
			swfBytes.endian = Endian.LITTLE_ENDIAN;
			
			if (isCompressed(swfBytes)) {
				uncompress(swfBytes);
			}
			
			var loader: Loader = new Loader();
			loader.name = "pageloader-" + String(page);
			loader.contentLoaderInfo.addEventListener(Event.COMPLETE, m_pageLoadHandler);
			loader.loadBytes(swfBytes, m_loaderCtx);
		}
		
		private function isCompressed(bytes:ByteArray):Boolean
		{
			return bytes[0] == 0x43;
		}
		
		private function uncompress(bytes:ByteArray):void
		{
			var cBytes:ByteArray = new ByteArray();
			cBytes.writeBytes(bytes, 8);
			bytes.length = 8;
			bytes.position = 8;
			cBytes.uncompress();
			bytes.writeBytes(cBytes);
			bytes[0] = 0x46;
			cBytes.length = 0;
		}
		
		//		
		private function ioErrorHandler(event:IOErrorEvent):void
		{
			m_documentLoadedErrorHandler.call(null, event.text);
		}
		
		//
		private function securityErrorHandler(event:SecurityErrorEvent):void
		{
			m_documentLoadedErrorHandler.call(null, event.text);
		}

		//
		public function dispatchEvent(event:Event):Boolean {
			return dispatcher.dispatchEvent(event);
		}
		
		//
		public function addEventListener(type:String, listener:Function, useCapture:Boolean = false, priority:int = 0, useWeakReference:Boolean = false):void {
			dispatcher.addEventListener(type, listener, useCapture, priority, useWeakReference);
		}
		
		//
		public function hasEventListener(type:String):Boolean {
			return dispatcher.hasEventListener(type);
		}
		
		//
		public function removeEventListener(type:String, listener:Function, useCapture:Boolean = false):void {
			dispatcher.removeEventListener(type, listener, useCapture);
		}
		
		//
		public function willTrigger(type:String):Boolean {
			return dispatcher.willTrigger(type);
		}				

	}
}
